#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

// 变量的声明与初始化
void func1() {
	int a, b = 10;
	int* p1 = &a;
	int* p2 = &b;
	*p2 = *p1; // 相当于b = a; 没有对变量a进行初始化却要使用a的值，会导致未定义行为
	printf("*p2 = %d\n", *p2);

	int* q = NULL;
	// *q = 0; // error，不能对空指针进行操作
	// printf("*q = %d\n", *q);

	char x, y, * z;
	x = '\xbc';
	y = '\0xab';
	z = "\017"; // '\0'是字符串结束符，因此z是一个空串
	printf("x = %c\n", x);
	printf("y = %c\n", y);
	printf("z = %s\n", z);
}

// 指针与数组
void func2() {
	int arr[10] = { 1, 2, 3, 4, 5 }, * p = arr; // p指向arr[0]
	printf("*p++ = %d\n", *p++); // 输出1，然后p指向arr[1]
	printf("*++p = %d\n", *++p); // p先指向arr[2]，再输出3
	printf("++*p = %d\n", ++ * p); // p仍指向arr[2]，但arr[2]被修改为4，输出4
	printf("(*p)++ = %d\n", (*p)++); // p仍指向arr[2]，输出4，但arr[2]被修改为5

	p = arr; // 以下四种写法等价
	printf("p[1] = %d\n", p[1]); // 2
	printf("arr[1] = %d\n", arr[1]); // 2
	printf("*(p + 1) = %d\n", *(p + 1)); // 2
	printf("*(arr + 1) = %d\n", *(arr + 1)); // 2

	// 数组名 是 数组的首元素地址：array == &array[0]; *array == array[0];
    // 数组名用于指针变量初始化时可以将其视为指向首元素的指针
    // 二维数组array：可以看成是 其中每个元素都是一维数组 的一个一维数组
    // array[1]是二维数组array的第二个元素，也就是一个一维数组
    // array[1]实际上也是一个数组名，可以被看作是一个指向int类型数组的指针
    // array是指向二维数组array的首元素地址的指针
    // 那么array[1]可以看做是指向一维数组array[1]首元素地址的指针
    int array[4][10] = { {1,2,3}, {4,5,6} ,{7,8,9}, {6,6,6} };
    int* p1, * p2, * q[4]; // q是一个指针数组
    p1 = array; // error：不能将int(*)[10]类型的值分配到int *类型的实体
    q[1] = array[1]; // q[1]是int *类型，array[1] == *(array + 1)
    p2 = array[1]; // array[1] == &array[1][0]; 即int *类型
    q[2] = &array[2][0]; // array[2][0]是int型数据，取地址后为int *
    printf("p1 = %d\n", *p1);
    printf("p2 = %d\n", *p2);
    printf("q[1] = %d\n", *q[1]);
    printf("q[2] = %d\n", *q[2]);

    // 对于一维数组
    arr[1] == *(arr + 1);
    // 对于二维数组
    array[1][2] == *(*(array + 1) + 2); // arr[i][j] == *(*(arr + i) + j)
}

// 数组与字符串
void func3() {
	char* str, * str2;
	str = "hello";
	// strcpy(str2, str); // error: C6001:使用未初始化的内存"str2"
	str2 = (char*)malloc(strlen(str) + 1);
	strcpy(str2, str);
	printf("str = %s\n", str);
	printf("str2 = %s\n", str2);

	char array[10];
	// char array1[]; // 错误：定义数组时，必须指明列的大小
	char array2[10] = "world"; // 只能在字符数组初始化时对整体赋值
	// array = "hello"; // error，只能对各个元素赋值，不能对字符数组整体赋值，或使用strcpy
	strcpy(array, str);
	// strcpy_s(array, strlen(str)+1, str);
	printf("array = %s\n", array);
	printf("array2 = %s\n", array2);
	free(str2);

	// char c1[3] = c2[3] = "ab"; // error：每个数组都需要独立的声明、初始化
}

// 指针与字符串
void func4() {
	char* s1, * s2;
	// *s1 = "hello world"; // s1是一个未初始化的指针，解引用一个未初始化的指针会导致未定义行为
	s1 = (char*)malloc(12 * sizeof(char)); // malloc开辟空间后必须使用strcpy，且不能更改指向
	// s1 = "666"; // 使s1指向了字符串常量，从而丢失了先前通过malloc分配的内存，导致内存泄漏
	strcpy(s1, "hello world");
	// *s1 = "HELLO WORLD"; // 错误：不能将char *类型的字符串赋值给char类型的变量
	s1[0] = 'H'; // 等价于 *s1 = 'H'; 即 *(s1 + 0)
	// strcpy(s2, "hello world"); // 错误：使用strcpy必须要先预留空间
	s2 = "hello world"; // 指针可以在定义后对整体赋值，数组在定义后只能对各个元素赋值或strcpy
	// s2[0] = 'H'; // 且char型指针s2指向了字符串常量，字符串常量存储在只读区域，不能被修改
	printf("s1 = %s\n", s1);
	printf("s2 = %s\n", s2);
	free(s1);
}

int main(void) {
	func1();
    func2();
    func3();
    func4();

	return 0;
}